package com.sojson.util.security.shiro.config.shiro;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.servlet.Filter;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;

import com.sojson.util.security.shiro.expand.realm.CustomModularRealmAuthenticator;
import com.sojson.util.security.shiro.interceptor.core.CustomAuthorizationAttributeSourceAdvisor;
import com.sojson.util.security.shiro.realm.impl.ShiroRealm;
import com.sojson.util.security.shiro.securityManager.CustomSecurityManager;
import com.sojson.util.security.shiro.shiroFilter.CustomShiroFilterFactoryBean;
import com.sojson.util.security.shiro.shiromanager.impl.CustomShiroManager;

import lombok.extern.slf4j.Slf4j;

/**
 * 配置shiro
 * 
 * @author liu
 * @date 2020-11-02
 */
@Slf4j
// @Configuration
public class ShiroConfig {

    // @Lazy //延迟加载 org.springframework.context.annotation.Lazy
    // @Order(0) // 执行顺序的优先级,而不是定义Bean的加载顺序,默认最小优先级,数值越小优先级越高
    // =======================================================================================================
    // ===============================================华丽的分割线===============================================
    // =======================================================================================================
    // /** session超时时间,默认是30分钟 */
    // private Long timeout = StringUtils.isNotBlankString(Constant.PROPERTIES.getProperty("so.session.timeout"))
    // ? Long
    // .valueOf(PropertiesUtils.getNumberFormat(Constant.PROPERTIES.getProperty("so.session.timeout")).toString())
    // : 1000 * 60 * 30L;
    // /** 是否开启检查session有效性 */
    // @Value("${so.session.validation.enabled:false}")
    // private Boolean validationEnabled;
    // /** 间隔多少时间检查session有效性,默认是1小时 */
    // private Long interval =
    // StringUtils.isNotBlankString(Constant.PROPERTIES.getProperty("so.session.validation.interval"))
    // ? Long.valueOf(PropertiesUtils
    // .getNumberFormat(Constant.PROPERTIES.getProperty("so.session.validation.interval")).toString())
    // : 1000 * 60 * 60L;
    // /** session的cookie的顶级域名,空白为不配置 */
    // @Value("${so.session.cookie.domain}")
    // private String sessionCookieDomain;
    // =======================================================================================================
    // ===============================================华丽的分割线===============================================
    // =======================================================================================================
    // /** 记住我多少天,以秒为单位,不设置为30天 */
    // private Integer maxAge =
    // StringUtils.isNotBlankString(Constant.PROPERTIES.getProperty("so.rememberMe.cookie.maxAge"))
    // ? Integer.valueOf(PropertiesUtils
    // .getNumberFormat(Constant.PROPERTIES.getProperty("so.rememberMe.cookie.maxAge")).toString())
    // : 60 * 60 * 24 * 30;
    // /** 记住我cookie的顶级域名,空白为不配置 */
    // @Value("${so.rememberMe.cookie.domain}")
    // private String rememberMeCookieDomain;

    // /**
    // * redis 的缓存
    // *
    // * @return
    // */
    // @Bean
    // public JedisManager jedisManager() {
    // log.info("JedisManager注入成功！");
    // return new JedisManager();
    // }
    //
    // /**
    // * session 创建、删除、查询
    // *
    // * @param jedisManager
    // * @return
    // */
    // @Bean
    // public CustomShiroSessionRepository customShiroSessionRepository() {
    // CustomShiroSessionRepository jedisShiroSessionRepository = new CustomShiroSessionRepository();
    // jedisShiroSessionRepository.setJedisManager(jedisManager());
    // log.info("customShiroSessionRepository注入成功！");
    // return jedisShiroSessionRepository;
    // }
    //
    // /**
    // *
    // ===========================================================================================================================
    // */
    // /**
    // * shiro 缓存实现,对ShiroCacheManager,我是采用redis的实现
    // *
    // * @param jedisManager
    // * @return
    // */
    // @Bean
    // public JedisShiroCacheManager jedisShiroCacheManager() {
    // JedisShiroCacheManager jedisShiroCacheManager = new JedisShiroCacheManager();
    // jedisShiroCacheManager.setJedisManager(jedisManager());
    // log.info("jedisShiroCacheManager注入成功！");
    // return jedisShiroCacheManager;
    // }
    //
    // /**
    // * 用户缓存
    // *
    // * @param jedisShiroCacheManager
    // * @return
    // */
    // @Bean
    // public CustomShiroCacheManager customShiroCacheManager() {
    // CustomShiroCacheManager customShiroCacheManager = new CustomShiroCacheManager();
    // customShiroCacheManager.setShiroCacheManager(jedisShiroCacheManager());
    // log.info("customShiroCacheManager注入成功！");
    // return customShiroCacheManager;
    // }
    //
    // /**
    // *
    // ===========================================================================================================================
    // */
    // /**
    // * 用户信息记住我功能的相关配置
    // *
    // * @return
    // */
    // @Bean
    // public SimpleCookie customRememberMeCookie() {
    // SimpleCookie simpleCookie = new SimpleCookie(ConstantByMap.REMEMBERME_COOKIE_NAME);
    // // 保证该系统不会受到跨域的脚本操作供给
    // simpleCookie.setHttpOnly(true);
    // // 定义Cookie的过期时间,单位为秒
    // simpleCookie.setMaxAge(maxAge);
    // // 记住我cookie的顶级域名,空白为不配置
    // if (StringUtils.isNotBlankObject(rememberMeCookieDomain)) {
    // simpleCookie.setDomain(rememberMeCookieDomain);
    // }
    // log.info("customRememberMeCookie注入成功！");
    // return simpleCookie;
    // }
    //
    // /**
    // * 记住我功能管理器
    // *
    // * @param rememberMeCookie
    // * @return
    // */
    // @Bean
    // public CookieRememberMeManager customRememberMeManager() {
    // CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
    // // rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度（128 256 512 位）
    // rememberMeManager.setCipherKey(Base64.decode(ConstantByMap.REMEMBERME_COOKIE_KEYS));
    // rememberMeManager.setCookie(customRememberMeCookie());
    // log.info("customRememberMeManager注入成功！");
    // return rememberMeManager;
    // }
    //
    // /**
    // *
    // ===========================================================================================================================
    // */
    // /**
    // * 配置需要向Cookie中保存数据的配置模版
    // *
    // * @return
    // */
    // @Bean
    // public SimpleCookie customSessionIdCookie() {
    // SimpleCookie simpleCookie = new SimpleCookie(ConstantByMap.SESSION_ID_NAME);
    // // 保证该系统不会受到跨域的脚本操作供给
    // simpleCookie.setHttpOnly(true);
    // // 定义Cookie的过期时间,单位为秒,如果设置为-1表示浏览器关闭,则Cookie消失
    // simpleCookie.setMaxAge(-1);
    // // session的cookie的顶级域名,空白为不配置
    // if (StringUtils.isNotBlankObject(sessionCookieDomain)) {
    // simpleCookie.setDomain(sessionCookieDomain);
    // }
    // log.info("customSessionIdCookie注入成功！");
    // return simpleCookie;
    // }
    //
    // /**
    // * 会话验证调度器,隔多久检查一次Session有效性,不配置默认1小时检查一次,我配置是为了让他少检查几次,让间隔时间多一点
    // *
    // * @param sessionManager
    // * @return
    // */
    // @Bean
    // public ExecutorServiceSessionValidationScheduler customSessionValidationScheduler() {
    // ExecutorServiceSessionValidationScheduler executorServiceSessionValidationScheduler =
    // new ExecutorServiceSessionValidationScheduler();
    // // 间隔多少时间检查session有效性,不配置是60分钟
    // executorServiceSessionValidationScheduler.setInterval(interval);
    // log.info("customSessionValidationScheduler注入成功！");
    // return executorServiceSessionValidationScheduler;
    // }

    // /**
    // * 实例注入,相当于调用sessionValidationScheduler.setSessionManager(sessionManager)
    // * 类路径需要修改
    // */
    // @Bean
    // public MethodInvokingFactoryBean
    //
    // executorServiceSessionValidationSchedulerSetSessionManagery() {
    // MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
    // // 调用哪个对象的实例方法
    // methodInvokingFactoryBean.setTargetObject(customSessionValidationScheduler());
    // // 要传入的参数
    // methodInvokingFactoryBean.setArguments(customSessionManager());
    // // 调用哪个实例方法
    // methodInvokingFactoryBean.setTargetMethod("setSessionManager");
    // log.info("给org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler注入customSessionManager成功！");
    // return methodInvokingFactoryBean;
    // }
    //
    // /**
    // * session监听器custom shiro session listener
    // *
    // * @param jedisShiroSessionRepository
    // * @return
    // */
    // @Bean
    // public CustomSessionListener customSessionListener() {
    // CustomSessionListener customSessionListener = new CustomSessionListener();
    // customSessionListener.setShiroSessionRepository(customShiroSessionRepository());
    // log.info("customSessionListener注入成功！");
    // return customSessionListener;
    // }
    //
    // /**
    // * 会话Session ID生成器
    // *
    // * @return
    // */
    // @Bean
    // public JavaUuidSessionIdGenerator customSessionIdGenerator() {
    // JavaUuidSessionIdGenerator javaUuidSessionIdGenerator = new JavaUuidSessionIdGenerator();
    // log.info("customSessionIdGenerator注入成功！");
    // return javaUuidSessionIdGenerator;
    // }
    //
    // /**
    // * 负责Session的持久化操作
    // *
    // * @param jedisShiroSessionRepository
    // * @param sessionIdGenerator
    // * @return
    // */
    // @Bean
    // public CustomShiroSessionDAO customShiroSessionDAO() {
    // CustomShiroSessionDAO customShiroSessionDAO = new CustomShiroSessionDAO();
    // customShiroSessionDAO.setShiroSessionRepository(customShiroSessionRepository());
    // customShiroSessionDAO.setSessionIdGenerator(customSessionIdGenerator());
    // customShiroSessionDAO.set
    // log.info("customShiroSessionDAO注入成功！");
    // return customShiroSessionDAO;
    // }
    //
    // /**
    // * 新学的,主要目的(Session工厂,负责创建Session)
    // *
    // * @return
    // */
    // @Bean
    // public CustomSessionFactory customSessionFactory() {
    // CustomSessionFactory customSessionFactory = new CustomSessionFactory();
    // log.info("customSessionFactory注入成功！");
    // return customSessionFactory;
    // }
    //
    // /**
    // * Session Manager
    // *
    // * @param customShiroSessionDAO
    // * @param customSessionListener
    // * @param sessionValidationScheduler
    // * @param sessionIdCookie
    // * @return
    // */
    // @Bean
    // public CustomSessionManager customSessionManager() {
    // CustomSessionManager sessionManager = new CustomSessionManager();
    //
    // // 相隔多久检查一次session的有效性
    // sessionManager.setSessionValidationInterval(interval);
    // // session超时时间
    // sessionManager.setGlobalSessionTimeout(timeout);
    // sessionManager.setSessionDAO(customShiroSessionDAO());
    // // =============================================================================================
    // ArrayList<SessionListener> arrayList = new ArrayList<>();
    // arrayList.add(customSessionListener());
    // log.info("customSessionListener监听器已添加到sessionManager中！");
    // // session 监听,可以多个
    // sessionManager.setSessionListeners(arrayList);
    // // =============================================================================================
    // ExecutorServiceSessionValidationScheduler customSessionValidationScheduler = customSessionValidationScheduler();
    // customSessionValidationScheduler.setSessionManager(sessionManager);
    // sessionManager.setSessionValidationScheduler(customSessionValidationScheduler);
    // // =============================================================================================
    // // 是否开启 检测,默认开启
    // sessionManager.setSessionValidationSchedulerEnabled(validationEnabled);
    // // 是否删除无效的,默认也是开启
    // sessionManager.setDeleteInvalidSessions(true);
    // sessionManager.setSessionIdCookie(customSessionIdCookie());
    // sessionManager.setSessionFactory(customSessionFactory());
    //
    // log.info("customSessionManager注入成功！");
    // return sessionManager;
    // }

    /**
     * ===========================================================================================================================
     */
    /**
     * 授权 认证
     * 
     * @param jedisShiroSessionRepository
     * @param sessionIdGenerator
     * @return
     */
    @Bean
    public ShiroRealm customShiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        log.info("customShiroRealm注入成功！");
        return shiroRealm;
    }

    /**
     * 新学的,主要目的(Realm抛异常的时候,如果是自己定义的异常就直接抛,不捕获)
     * 
     * @return
     */
    @Bean
    public CustomModularRealmAuthenticator customModularRealmAuthenticator() {
        CustomModularRealmAuthenticator customModularRealmAuthenticator = new CustomModularRealmAuthenticator();
        log.info("customModularRealmAuthenticator注入成功！");
        return customModularRealmAuthenticator;
    }

    /**
     * 新学的,主要目的()
     * 
     * @return
     */
    @Bean
    public DefaultWebSubjectFactory customSubjectFactory() {
        DefaultWebSubjectFactory customDefaultWebSubjectFactory = new DefaultWebSubjectFactory();
        log.info("customSubjectFactory注入成功！");
        return customDefaultWebSubjectFactory;
    }

    /**
     * 新学的,主要目的(负责Subject的持久化操作,类似SessionDao)
     * 
     * @return
     */
    @Bean
    public DefaultSubjectDAO customSubjectDAO() {
        DefaultSubjectDAO customDefaultSubjectDAO = new DefaultSubjectDAO();

        // 关闭Session
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        customDefaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        log.info("customSubjectDAO注入成功！");
        return customDefaultSubjectDAO;
    }

    /**
     * 安全管理器,(重写它是为了优化)
     * 
     * @param shiroRealm
     * @param sessionManager
     * @param rememberMeManager
     * @param customShiroCacheManager
     * @return
     */
    @Bean
    public CustomSecurityManager customSecurityManager() {
        CustomSecurityManager securityManager = new CustomSecurityManager();

        // securityManager.setSessionManager(customSessionManager());
        // securityManager.setRememberMeManager(customRememberMeManager());
        // securityManager.setCacheManager(customShiroCacheManager());
        // =============================================================================================
        ArrayList<Realm> realms = new ArrayList<>();
        realms.add(customShiroRealm());
        securityManager.setRealms(realms);
        // =============================================================================================
        CustomModularRealmAuthenticator modularRealmAuthenticator = customModularRealmAuthenticator();
        modularRealmAuthenticator.setRealms(securityManager.getRealms());
        securityManager.setAuthenticator(modularRealmAuthenticator);
        // =============================================================================================
        securityManager.setSubjectFactory(customSubjectFactory());
        securityManager.setSubjectDAO(customSubjectDAO());

        log.info("customSecurityManager注入成功！");
        return securityManager;
    }

    /**
     * ===========================================================================================================================
     */
    /**
     * 过滤器加载的时候会加载次对象 需要添加过滤器
     * 
     * @param securityManager
     * @param kickoutSessionFilter
     * @param shiroManager
     * @return
     * @throws IOException 
     */
    @Bean
    public CustomShiroFilterFactoryBean customShiroFilterFactoryBean() throws IOException {
        CustomShiroFilterFactoryBean shiroFilter = new CustomShiroFilterFactoryBean();
        // =============================================================================================
        shiroFilter.setSecurityManager(customSecurityManager());
        // =============================================================================================
        // 登录页面
        // shiroFilter.setLoginUrl(ShiroConstantByMap.LOGIN_URL);
        // 成功页面,暂时不知道是啥
        // shiroFilter.setSuccessUrl(ShiroConstantByMap.SUCCESS_URL);
        // 权限不足的错误提示页面
        // shiroFilter.setUnauthorizedUrl(ShiroConstantByMap.UNAUTHORIZED_URL);
        // =============================================================================================
        // 加载请求拦截的对应路径
        shiroFilter.setFilterChainDefinitions(shiroManager().loadFilterChainDefinitions());
        // =============================================================================================
        // 添加过滤器链
        shiroFilter.setFilters(getFilters());
        // =============================================================================================
        log.info("customShiroFilterFactoryBean注入成功！");
        return shiroFilter;
    }

    public HashMap<String, Filter> getFilters() {
        HashMap<String, Filter> hashMap = new HashMap<>(7);
        // String permiName = null;

        // permiName = "login";
        // hashMap.put(permiName, new PassThruAuthenticationFilter());
        // log.info("登录验证过滤器(PassThruAuthenticationFilter)注入成功,过滤权限为" + permiName);

        // if (KickoutSessionFilterInterface.KICKOUT_TYPE != KickoutSessionFilterInterface.KICKOUT_NO) {
        // permiName = "kickout";
        // hashMap.put(permiName, new KickoutSessionFilter());
        // log.info("帐号多地登录踢出策略过滤器(KickoutSessionFilter)注入成功,过滤权限为" + permiName);
        // }
        //
        // permiName = "login";
        // hashMap.put(permiName, new ShiroLoginFilter());
        // log.info("登录验证过滤器(ShiroLoginFilter)注入成功,过滤权限为" + permiName);
        //
        // permiName = "perms";
        // hashMap.put(permiName, new PermissionFilter());
        // log.info("权限验证过滤器(PermissionFilter)注入成功,过滤权限为" + permiName);
        //
        // permiName = "roles";
        // hashMap.put(permiName, new RoleFilter());
        // log.info("角色验证过滤器(RoleFilter)注入成功,过滤权限为" + permiName);

        return hashMap;
    }

    /**
     * ===========================================================================================================================
     */
    /**
     * 负责读取shiro的权限列表
     * 
     * @return
     */
    @Bean
    public CustomShiroManager shiroManager() {
        CustomShiroManager shiroManager = new CustomShiroManager();
        log.info("shiroManager注入成功！");
        return shiroManager;
    }

    /**
     * ===========================================================================================================================
     */
    /**
     * 静态注入,相当于调用SecurityUtils.setSecurityManager(securityManager)
     * 
     * @param securityManager
     * @return
     */
    @Bean
    public MethodInvokingFactoryBean securityUtilsSetSecurityManager() {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        // 要传入的参数
        methodInvokingFactoryBean.setArguments(customSecurityManager());
        // 调用哪个类的哪个静态方法
        methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        log.info("给org.apache.shiro.SecurityUtils注入customSecurityManager成功！");
        return methodInvokingFactoryBean;
    }

    /**
     * ===========================================================================================================================
     */
    /**
     * shiro生命周期处理器（因为有bug所以单独放到了LifecycleBeanPostProcessorConfig类中,如果放到这会导致读取不到properties属性）
     */
    /**
     * ===========================================================================================================================
     */
    /**
     * 开启shiro自动代理
     * 
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        log.info("defaultAdvisorAutoProxyCreator注入成功！");
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * ===========================================================================================================================
     */
    /**
     * 配置切面类(1.注解要用)
     * 
     * @return
     */
    @Bean
    public CustomAuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        CustomAuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
            new CustomAuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(customSecurityManager());
        log.info("authorizationAttributeSourceAdvisor注入成功！");
        return authorizationAttributeSourceAdvisor;
    }

    // /**
    // * 配置切面类
    // *
    // * @return
    // */
    // @Bean
    // public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
    // AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
    // new AuthorizationAttributeSourceAdvisor();
    // authorizationAttributeSourceAdvisor.setSecurityManager(customSecurityManager());
    // log.info("authorizationAttributeSourceAdvisor注入成功！");
    // return authorizationAttributeSourceAdvisor;
    // }

}